﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Interactivity;
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Configuration;

using System.Data;
using System.Windows.Data;

using System.Reflection;
using System.Diagnostics;

using UCM;

namespace Behaviors
{

    public class WPFDataGridConfigurationBehavior : Behavior<System.Windows.DependencyObject>
    {

        #region "public Properties"


        public bool DontPersistVisibleColumns { get; set; }
        public bool DontPersistColumnsOrder { get; set; }

        public string ColumnNameFilters { get; set; }
        public string ContextMenuChoices
        {
            get { return _ContextMenuChoices; }
            set { _ContextMenuChoices = value; }
        }
        public string ViewingColsFormat
        {
            get { return _ViewingColsFormat; }
            set { _ViewingColsFormat = value; }
        }

        public Label lblViewingCols;

        private string _dataGridName;
        public string dataGridName
        {
            get { return _dataGridName; }
            set { _dataGridName = value; }
        }


        #endregion "public Properties"

        #region "private Properties"

        private string _ContextMenuChoices = "Alphabetcal Menu,Show All Columns,Freeze Columns,Row Numbers,Filter Columns By,All {0} Columns";
        private string _ViewingColsFormat = "(viewing {0} of {1} columns)";

        private DataGrid dataGrid;
        private GroupBox groupBox;

        Brush labelFore;
        double labelHeight;
        private ContextMenu theContextMenu; // Context Menu for the field chooser.

        private string AllColumnsHeaders { get; set; }
        private string AllColumnDisplayIndexes { get; set; }

        private int nBaseItems = 5;
        private MenuItem mnuAlpha;
        private MenuItem mnuFilterCols;
        private MenuItem mnuShowAll;
        private MenuItem mnuFreeze;
        private MenuItem mnuRowHeaders;

        private List<Key> keysToIgnore = new List<Key>() { Key.LeftCtrl, Key.RightCtrl, Key.LeftAlt, Key.RightAlt, Key.System };

        private int HeaderColumnIndex;

        private string wordFilter = "";


        #endregion "Private Properties"

        protected override void OnAttached()
        {
            try
            {
                base.OnAttached();

                dataGrid = this.AssociatedObject as DataGrid;
                if (_dataGridName == null) _dataGridName = dataGrid.Name;

                contextMenu_BuildStaticMenu();

                dataGrid.Loaded += (sender, e) => { dataGrid_Loaded(); };
                dataGrid.AutoGeneratedColumns += new EventHandler(dataGrid_AutoGeneratedColumns);
                dataGrid.TargetUpdated += new EventHandler<DataTransferEventArgs>(dataGrid_TargetUpdated);

                dataGrid.ColumnReordered += (sender, e) => { dataGrid_ColumnReordered(sender); };

                dataGrid.ContextMenuOpening += (sender, e) => { dataGrid_ContextMenuOpening(e); };

                dataGrid.LoadingRow += (sender, e) => { e.Row.Header = (e.Row.GetIndex() + 1).ToString(); };

                dataGrid.RowHeaderWidth = 0;
                Style ns = new Style(typeof(DataGridRowHeader)) { BasedOn = dataGrid.RowHeaderStyle };
                ns.Setters.Add(new Setter(DataGridRowHeader.FontWeightProperty, FontWeights.Bold));
                ns.Setters.Add(new Setter(DataGridRowHeader.FontSizeProperty, 11.0));
                //ns.Setters.Add(new Setter(DataGridRowHeader.BackgroundProperty, new SolidColorBrush(Colors.Transparent)));
                ns.Setters.Add(new Setter(DataGridRowHeader.PaddingProperty, new Thickness(4, 0, 4, 0)));
                dataGrid.RowHeaderStyle = ns;


            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }

        private void dataGrid_TargetUpdated(object sender, DataTransferEventArgs e)
        {
            dataGrid.Columns[0].Width = 0;
            dataGrid.UpdateLayout();
            dataGrid.Columns[0].Width = new DataGridLength(1, DataGridLengthUnitType.Star);
        }

        void dataGrid_AutoGeneratedColumns(object sender, EventArgs e)
        {
            dataGrid_Loaded();
        }

        private void groupBox_AttachHeaderUI()
        {
            try
            {
                groupBox = WPFDataGridConfigurationBehaviorFinder.LastVisualAncestorOfType<GroupBox>(dataGrid);

                if (groupBox == null) try { groupBox = (GroupBox)dataGrid.Parent; }
                    catch { }

                if (groupBox == null) return;
                ///
                /// Get the groupBox header's stackpanel child
                /// and the foreground color from it's first label/textblock
                /// 
                StackPanel headerPanel = groupBox.Header as StackPanel;
                if (headerPanel == null)
                    return;

                Label lblLabel = headerPanel.Children[0] as Label;
                TextBlock txtLabel = headerPanel.Children[0] as TextBlock;
                if (lblLabel == null && txtLabel == null)
                    return;
                else if (lblLabel != null)
                {
                    labelFore = lblLabel.Foreground;
                    labelHeight = lblLabel.Height;
                }
                else
                {
                    labelFore = txtLabel.Foreground;
                    labelHeight = txtLabel.Height;
                }
                ///
                /// Add lblViewingCols
                /// 
                lblViewingCols = new Label() { Margin = new Thickness(12, 0, 0, 0), FontSize = 10, Foreground = labelFore };
                headerPanel.Children.Add(lblViewingCols);

            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
        }

        #region "DataGrid Events"


        private void dataGrid_ContextMenuOpening(ContextMenuEventArgs e)
        {
            try
            {
                DependencyObject dep = (DependencyObject)e.OriginalSource;

                // iteratively traverse the visual tree
                while ((dep != null) && !(dep is DataGridCell) && !(dep is DataGridColumnHeader))
                    dep = VisualTreeHelper.GetParent(dep);

                if (dep == null)
                    return;

                if (dep is DataGridColumnHeader)
                {
                    DataGridColumnHeader columnHeader = dep as DataGridColumnHeader;
                    // do something
                    HeaderColumnIndex = columnHeader.Column.DisplayIndex;
                }

                if (dep is DataGridCell)
                {
                    DataGridCell cell = dep as DataGridCell;
                    // navigate further up the tree
                    while ((dep != null) && !(dep is DataGridRow))
                        dep = VisualTreeHelper.GetParent(dep);

                    DataGridRow row = dep as DataGridRow;

                    int index = dataGrid.ItemContainerGenerator.IndexFromContainer(row);
                }
            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }

        private void dataGrid_ColumnReordered(object sender)
        {
            settings_SaveDisplayIndexes(sender);

            contextMenu_BuildMenu();
        }

        private void dataGrid_Loaded()
        {
            //try
            //{
            groupBox_AttachHeaderUI();

            contextMenu_BuildMenu(false);

            VisibleColumns_Initialize();

            // Set Frozen columns
            List<string> saVisibleColumns = VisibleColumns.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
            if (saVisibleColumns != null && saVisibleColumns.Count > 0 && saVisibleColumns[saVisibleColumns.Count - 1].StartsWith("-"))
                if (dataGrid != null)
                {
                    HeaderColumnIndex = Convert.ToInt16(saVisibleColumns[saVisibleColumns.Count - 1].Substring(1));
                    if (HeaderColumnIndex > 0) mnuFreeze.IsChecked = true;
                }


            //}
            //catch (Exception ex)
            //{ StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }

        }

        private void dataGrid_FreezeColumns()
        {
            try
            {
                dataGrid.FrozenColumnCount = HeaderColumnIndex;
                mnuFreeze.IsChecked = HeaderColumnIndex > 0;
                mnuFreeze.Header =
                    ContextMenuChoices.Split(',')[2] + "   " + "".PadRight(dataGrid.FrozenColumnCount, '□') + "|";
                settings_SaveFrozenColumnCount();
            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }




        #endregion "DataGrid Events"

        #region "ContextMenu Methods and Events"

        private void contextMenu_BuildStaticMenu()
        {
            try
            {
                // mnuFrozenRetain()
                theContextMenu = new ContextMenu() { FontSize = 11, StaysOpen = true };
                //theContextMenu.KeyDown += (server, e) => { wordFilter = e.Key.ToString(); contextMenu_BuildMenu(); };
                theContextMenu.PreviewKeyDown += (server, e) => { ContextMenu_PreviewKeyDown(e); };

                mnuAlpha = new MenuItem() { Header = ContextMenuChoices.Split(',')[0], FontWeight = FontWeights.Bold, IsCheckable = true, StaysOpenOnClick = true };
                mnuAlpha.Click += (sender, e) => { contextMenu_BuildMenu(); };

                mnuShowAll = new MenuItem() { Header = ContextMenuChoices.Split(',')[1], FontWeight = FontWeights.Bold, IsCheckable = true, StaysOpenOnClick = true };
                mnuShowAll.Checked += (sender, e) => { VisibleColumns = AllColumnsHeaders; };
                mnuShowAll.Click += (sender, e) => { if (mnuShowAll.IsChecked == false) VisibleColumns_Initialize(); };

                mnuFreeze = new MenuItem() { Header = ContextMenuChoices.Split(',')[2], FontWeight = FontWeights.Bold, IsCheckable = true, StaysOpenOnClick = true };
                mnuFreeze.Checked += (sender, e) => { dataGrid_FreezeColumns(); };
                mnuFreeze.Unchecked += (sender, e) => { HeaderColumnIndex = 0; dataGrid_FreezeColumns(); };

                mnuRowHeaders = new MenuItem() { Header = ContextMenuChoices.Split(',')[3], FontWeight = FontWeights.Bold, IsCheckable = true, StaysOpenOnClick = true };
                mnuRowHeaders.Checked += (sender, e) => { dataGrid.RowHeaderWidth = double.NaN; };
                mnuRowHeaders.Unchecked += (sender, e) => { dataGrid.RowHeaderWidth = 0; };

                mnuFilterCols_BuildSubMenu();

                if (mnuFilterCols != null) theContextMenu.Items.Add(mnuFilterCols);
                theContextMenu.Items.Add(mnuShowAll);
                theContextMenu.Items.Add(mnuFreeze);
                theContextMenu.Items.Add(mnuAlpha);
                theContextMenu.Items.Add(mnuRowHeaders);

            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }

        }

        private void ContextMenu_PreviewKeyDown(KeyEventArgs e)
        {

            if (e.Key == Key.Escape)
            {
                wordFilter = "";
                contextMenu_BuildMenu();
            }
            //else

            //    if (e.Key.ToString().Length==1)
            //    {
            //        wordFilter = e.Key.ToString();
            //        contextMenu_BuildMenu();
            //    }

        }

        private void mnuFilterCols_BuildSubMenu()
        {
            try
            {
                if (ColumnNameFilters != null)
                {
                    mnuFilterCols = new MenuItem() { Header = ContextMenuChoices.Split(',')[3], FontWeight = FontWeights.Bold };
                    string[] saFilters = ColumnNameFilters.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (string sFilter in saFilters)
                    {
                        string sTagText = sFilter;
                        string sMenuTexts = sFilter;
                        if (sFilter.Contains("|"))
                        {
                            sMenuTexts = sFilter.Split('|')[0];
                            sTagText = sFilter.Split('|')[1];
                        }

                        MenuItem mnuFilter = new MenuItem() { Header = string.Format(ContextMenuChoices.Split(',')[4], sMenuTexts), IsCheckable = true, StaysOpenOnClick = true, Tag = sTagText };
                        mnuFilter.Unchecked += (sender, e) => { mnuFilter_Unchecked(); };
                        mnuFilter.Checked += (sender, e) => { mnuFilter_Checked(sender); };
                        mnuFilterCols.Items.Add(mnuFilter);
                    }
                }
            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }

        private void mnuFilter_Checked(object sender)
        {
            try
            {
                contextMenu_mnuFilterCols_ClearCheckmarks(((MenuItem)sender).Tag.ToString());
                wordFilter = ((MenuItem)sender).Tag.ToString();
                contextMenu_BuildMenu();
            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }

        private void mnuFilter_Unchecked()
        {
            wordFilter = "";
            contextMenu_BuildMenu();
        }

        private void mnuFilterCols_Checked()
        {

        }


        private void contextMenu_BuildMenu(bool pbRebuild = true)
        {
            //try
            //{            // Remove any old column name items
            for (int i = theContextMenu.Items.Count - 1; i > 0; i--)
                if (((MenuItem)theContextMenu.Items[i]).FontWeight != FontWeights.Bold)
                    theContextMenu.Items.Remove(theContextMenu.Items[i]);

            nBaseItems = theContextMenu.Items.Count;

            // Attach the context menu to the DataGrid ColumnHeaders
            var headersPresenter = WPFDataGridConfigurationBehaviorFinder.FindChild<DataGridColumnHeadersPresenter>(dataGrid);
            ContextMenuService.SetContextMenu(headersPresenter, theContextMenu);

            if (VisibleColumns == null)
                throw (new SettingsPropertyNotFoundException("User's VisibleColumns setting not found."));

            // Get the current column ordering from user.config

            if (DisplayIndexes == null)
                throw (new SettingsPropertyNotFoundException("User's DisplayIndexes setting not found."));

            AllColumnDisplayIndexes = DisplayIndexes;
            string[] colIndexes = AllColumnDisplayIndexes.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

            System.Linq.IOrderedEnumerable<DataGridColumn> dataGridColumns = dataGrid.Columns.OrderBy(x => x.DisplayIndex);

            // Sort the columns in display index order so menu header order matchs display column order
            if (pbRebuild == false)
                // Initially the datagrid column order is such that display indexes are the same as the col indexes
                if (colIndexes.Length > 0)
                    dataGridColumns = dataGrid.Columns.OrderBy(x => Convert.ToInt16(colIndexes[x.DisplayIndex]));

            if (mnuAlpha.IsChecked)
                dataGridColumns = dataGrid.Columns.OrderBy(x => x.Header.ToString());

            System.Linq.IOrderedEnumerable<DataGridColumn> filteredDataGridColumns = null;
            if (wordFilter.Length > 1)
                filteredDataGridColumns = dataGrid.Columns
                    .Where(x => x.Header.ToString().Contains(wordFilter) == true).OrderBy(x => x.Header.ToString());
            if (filteredDataGridColumns != null) dataGridColumns = filteredDataGridColumns;

            if (wordFilter.Length == 1)
                dataGridColumns = dataGrid.Columns
                    .Where(x => x.Header.ToString().ToUpper().StartsWith(wordFilter.ToUpper()) == true).OrderBy(x => x.Header.ToString());

            AllColumnsHeaders = "";
            foreach (DataGridColumn col in dataGridColumns)
            {
                // All column name to a list of all column headers for later use.
                AllColumnsHeaders = String.Format("{0};{1}", col.Header.ToString().Replace("\n", " ").Replace("\r", " "), AllColumnsHeaders);

                // Add new menu item in display order.
                contextMenu_AddNewMenuItem(col);
            }

            string sTemp = VisibleColumns;
            VisibleColumns = null;
            VisibleColumns = sTemp;
            //}
            //catch (Exception ex)
            //{ StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }

        }

        private void contextMenu_AddNewMenuItem(DataGridColumn col)
        {
            try
            {
                MenuItem menuItem = new MenuItem() { Header = col.Header.ToString().Replace("\n", " ").Replace("\r", " "), StaysOpenOnClick = true };
                List<string> saVisibleColumns = new List<String>() { "" };
                if (VisibleColumns != null)
                    saVisibleColumns = VisibleColumns.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();

                //menuItem.Icon = new Image() { Source = Application.Current.Resources["Checkmark"] as ImageSource };
                //((Image)menuItem.Icon).Visibility = (saVisibleColumns.Contains(menuItem.Header) || VisibleColumns == null) ? Visibility.Visible : Visibility.Collapsed;

                menuItem.IsChecked = (saVisibleColumns.Contains(menuItem.Header));
                menuItem.Click += (sender, e) => { contextMenu_ColumnName_Click(sender); };

                theContextMenu.Items.Add(menuItem);

            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }

        private void contextMenu_ColumnName_Click(object sender)
        {
            try
            {
                MenuItem mi = sender as MenuItem;

                // Get the column name that was clicked
                string colName = mi.Header.ToString();

                // Get the clicked menu item's icon (checkmark image)  
                //Image icon = mi.Icon as Image;

                // Capture new visible columns list
                settings_SaveVisibleColumns(mi, colName);

                //dataGrid.InvalidateMeasure();
                //dataGrid.UpdateLayout();           
            }

            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }

        }

        private void contextMenu_mnuFilterCols_ClearCheckmarks(string s)
        {
            try
            {
                foreach (MenuItem mi2 in mnuFilterCols.Items)
                    if (mi2.Tag.ToString() != s)
                        mi2.IsChecked = false;

                mnuShowAll.IsChecked = false;
            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }


        #endregion "ContextMenu Methods and Events"

        #region "Settings Methods"

        private void settings_SaveVisibleColumns(MenuItem mi, string colName)
        {

            try
            {
                if (theContextMenu.Items.Count - nBaseItems < dataGrid.Columns.Count)
                    return;

                // Put the visible column names into an array
                List<string> saVisibleColumns = VisibleColumns.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                if (saVisibleColumns != null && saVisibleColumns.Count > 0 && saVisibleColumns[saVisibleColumns.Count - 1].StartsWith("-"))
                    saVisibleColumns.RemoveAt(saVisibleColumns.Count - 1);

                // If the menu item is unchecked (column is not visible)
                if (!mi.IsChecked)
                    // Make the column visible by adding its name to the Visible Columns list
                    saVisibleColumns.Add(colName);

                else
                    // Hide the column by removing its name from the VisibleColumns list
                    if (saVisibleColumns.Contains(colName) && saVisibleColumns.Count > 1)
                        saVisibleColumns.Remove(colName);

                VisibleColumns = String.Join(";", saVisibleColumns) + ";-" + dataGrid.FrozenColumnCount.ToString();

            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }

        private void settings_SaveFrozenColumnCount()
        {
            try
            {
                List<string> saVisibleColumns = VisibleColumns.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                if (saVisibleColumns != null && saVisibleColumns.Count > 0 && saVisibleColumns[saVisibleColumns.Count - 1].StartsWith("-"))
                    saVisibleColumns.RemoveAt(saVisibleColumns.Count - 1);

                VisibleColumns = String.Join(";", saVisibleColumns) + ";-" + dataGrid.FrozenColumnCount.ToString();
            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }

        private void settings_SaveDisplayIndexes(object sender)
        {
            try
            {            // Capture the new column order
                AllColumnDisplayIndexes = "";
                foreach (DataGridColumn col in ((DataGrid)sender).Columns)
                {
                    AllColumnDisplayIndexes += (AllColumnDisplayIndexes.Length > 0 ? ";" : "") + col.DisplayIndex.ToString();
                }

                DisplayIndexes = AllColumnDisplayIndexes;

            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }

        private void settings_PersistVisibleColumns(List<string> saVisibleColumns)
        {
            try
            {
                VisibleColumns = String.Join(";", saVisibleColumns) + ";-" + dataGrid.FrozenColumnCount.ToString();


            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }

        private void settings_PropertyNotFound(SettingsPropertyNotFoundException pex)
        {
            try
            {
                MessageBoxResult res = MessageBox.Show(pex.Message + "\n\nWould you like this setting name to be copied to the clipboard?",
                this.GetType().ToString() + " requires a missing setting name",
                MessageBoxButton.YesNoCancel, MessageBoxImage.Exclamation);

                if (res == MessageBoxResult.Yes)
                {
                    if (pex.Message.Contains("VisibleColumns"))
                        Clipboard.SetData(DataFormats.Text, dataGridName + "VisibleColumns");
                    else
                        Clipboard.SetData(DataFormats.Text, dataGridName + "DisplayIndexes");
                }
            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }

        #endregion "Settings Methods"

        #region DisplayIndexes (DependencyProperty)
        public string DisplayIndexes
        {
            get { return (string)GetValue(DisplayIndexesProperty); }
            set { SetValue(DisplayIndexesProperty, value); }
        }

        public static readonly DependencyProperty DisplayIndexesProperty =
    DependencyProperty.Register(
        "DisplayIndexes",
        typeof(string),
        typeof(WPFDataGridConfigurationBehavior),
        new PropertyMetadata("", new PropertyChangedCallback(OnDisplayIndexesChanged))
        );

        private static void OnDisplayIndexesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((WPFDataGridConfigurationBehavior)d).DisplayIndexesChanged(e);
        }

        public void DisplayIndexesChanged(DependencyPropertyChangedEventArgs e)
        {
            // Persist the new column order
            if (dataGrid != null && !DontPersistColumnsOrder)
                App.Settings_Save(dataGridName + "DisplayIndexes", AllColumnDisplayIndexes);
        }

        #endregion "DisplayIndexes (DependencyProperty)"

        #region VisibleColumns (DependencyProperty)

        /// <summary>
        /// 
        /// Gets or sets a value indicating the names of columns 
        /// (as they appear in the column header) to be visible, seperated by a semicolon.
        /// 
        /// Columns whose names are not here will be hidden.
        /// </summary>

        public string VisibleColumns
        {
            get { return (string)GetValue(VisibleColumnsProperty); }
            set { SetValue(VisibleColumnsProperty, value); }
        }

        private void VisibleColumns_Initialize()
        {
            // Get saved VisibleColumns from app.config
            try
            {
                // Initialize VisibleColumns
                VisibleColumns = String.IsNullOrEmpty(VisibleColumns.ToString().Replace("\n", " ").Replace("\r", " ")) ? AllColumnsHeaders : VisibleColumns;
            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }


        public static readonly DependencyProperty VisibleColumnsProperty =
            DependencyProperty.Register(
                "VisibleColumns",
                typeof(string),
                typeof(WPFDataGridConfigurationBehavior),
                new PropertyMetadata("", new PropertyChangedCallback(OnVisibleColumnsChanged))
                );

        private static void OnVisibleColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((WPFDataGridConfigurationBehavior)d).VisibleColumnsChanged(e);
        }



        /// <summary>
        /// 
        /// Updates the display
        /// 
        /// </summary>
        /// <param name="e"></param>

        public void VisibleColumnsChanged(DependencyPropertyChangedEventArgs e)
        {
            try
            {
                if (theContextMenu == null)
                    return;

                if (e.NewValue != null)
                {
                    string[] showTheseColumns = e.NewValue.ToString().Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                    List<string> saContextMenuVisibleItems = new List<string>();

                    int iCol = 0;

                    foreach (MenuItem menuItem in theContextMenu.Items)
                    {
                        // Show/Hide the Context Menu item's checkmark.
                        //((Image)menuItem.Icon).Visibility =
                        //    showTheseColumns.Contains(menuItem.Header.ToString()) ? Visibility.Visible : Visibility.Collapsed;
                        if (menuItem.FontWeight == FontWeights.Bold) continue;

                        menuItem.IsChecked = showTheseColumns.Contains(menuItem.Header.ToString());
                        if (menuItem.IsChecked) saContextMenuVisibleItems.Add(menuItem.Header.ToString());

                        mnuShowAll.IsChecked = mnuShowAll.IsChecked && menuItem.IsChecked;

                        // Assign menu item's column's DisplayIndex in display order, (i.e. in menu item order), looking up each column by header name.)
                        if (mnuAlpha.IsChecked == false)
                            ((DataGridColumn)dataGrid.Columns.Where(x => x.Header.ToString().Replace("\n", " ").Replace("\r", " ") == menuItem.Header.ToString()).First()).DisplayIndex = iCol++;
                    }

                    if (mnuFilterCols != null)
                        foreach (MenuItem mnuiFilter in mnuFilterCols.Items)
                            mnuiFilter.IsEnabled = e.NewValue.ToString().Contains(mnuiFilter.Tag.ToString());

                    // Show the columns
                    foreach (DataGridColumn col in dataGrid.Columns)
                        col.Visibility = showTheseColumns.Contains(col.Header.ToString().Replace("\n", " ").Replace("\r", " "))
                              && (saContextMenuVisibleItems.Contains(col.Header.ToString().Replace("\n", " ").Replace("\r", " ")))
                            ? Visibility.Visible : Visibility.Collapsed;


                    if (lblViewingCols != null)
                        lblViewingCols.Content = String.Format(ViewingColsFormat, showTheseColumns.Count(), AllColumnsHeaders.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Count());

                    // Persist the new visible columns list

                    if (dataGrid != null && !DontPersistVisibleColumns)
                        App.Settings_Save(dataGridName + "VisibleColumns", VisibleColumns);

                }
            }
            catch (Exception ex)
            { StdErrOut(ex, MethodInfo.GetCurrentMethod().Name); }
        }

        #endregion "VisibleColumns"


        private void StdErrOut(Exception ex, string MethodName)
        {
            if (ex is System.Configuration.SettingsPropertyNotFoundException)
            {
                settings_PropertyNotFound(ex as SettingsPropertyNotFoundException);
            }
            else
                WPFDataGridConfigurationBehaviorStdErr.StdError(ex, MethodName);

        }
    }

    #region "Helper Classes"

    public static class WPFDataGridConfigurationBehaviorFinder
    {
        public static T FindChild<T>(DependencyObject depObj) where T : DependencyObject
        {
            try
            {
                // Confirm obj is valid. 
                if (depObj == null) return null;

                // success case
                if (depObj is T) return depObj as T;

                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
                {
                    T obj = FindChild<T>(VisualTreeHelper.GetChild(depObj, i));
                    if (obj != null) return obj;
                }
            }
            catch (Exception ex)
            { WPFDataGridConfigurationBehaviorStdErr.StdError(ex, MethodInfo.GetCurrentMethod().Name); }
            return null;
        }

        public static T FindChildNamed<T>(DependencyObject depObj, string psNamed) where T : DependencyObject
        {
            try
            {
                // Confirm obj is valid. 
                if (depObj == null) return null;

                // success case
                if (depObj is T)
                {

                    if (depObj is Label)
                    {
                        if (((Label)depObj).Name == psNamed) return depObj as T;
                    }
                    else
                        if (depObj is TextBlock)
                        {
                            if (((TextBlock)depObj).Name == psNamed) return depObj as T;
                        }
                        else
                        {
                            if (depObj is TextBox)
                                if (((TextBox)depObj).Name == psNamed) return depObj as T;
                        }
                }

                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
                {
                    T obj = FindChildNamed<T>(VisualTreeHelper.GetChild(depObj, i), psNamed);
                    if (obj != null) return obj;
                }

            }
            catch (Exception ex)
            { WPFDataGridConfigurationBehaviorStdErr.StdError(ex, MethodInfo.GetCurrentMethod().Name); }
            return null;
        }

        public static T _FirstVisualAncestorOfType<T>(this DependencyObject element) where T : DependencyObject
        {
            try
            {
                if (element == null) return null;

                var parent = VisualTreeHelper.GetParent(element) as DependencyObject;
                while (parent != null)
                {
                    if (parent is T)
                        return (T)parent;
                    if (parent is IBreakVisualParenting)
                    {
                        parent = ((IBreakVisualParenting)parent).Parent;
                    }
                    else
                        parent = VisualTreeHelper.GetParent(parent) as DependencyObject;
                }
            }
            catch (Exception ex)
            { WPFDataGridConfigurationBehaviorStdErr.StdError(ex, MethodInfo.GetCurrentMethod().Name); }
            return null;
        }

        public interface IBreakVisualParenting
        {
            DependencyObject Parent { get; }
        }

        public static T LastVisualAncestorOfType<T>(this DependencyObject element) where T : DependencyObject
        {
            T item = null; try
            {

                var parent = VisualTreeHelper.GetParent(element) as DependencyObject;
                while (parent != null)
                {
                    if (parent is T)
                        item = (T)parent;
                    if (parent is IBreakVisualParenting)
                    {
                        parent = ((IBreakVisualParenting)parent).Parent;
                    }
                    else
                        parent = VisualTreeHelper.GetParent(parent) as DependencyObject;
                }
            }
            catch (Exception ex)
            { WPFDataGridConfigurationBehaviorStdErr.StdError(ex, MethodInfo.GetCurrentMethod().Name); }
            return item;
        }

    }

    public static class WPFDataGridConfigurationBehaviorStdErr
    {
        public static void StdError(Exception ex, string MethodName)
        {
            MessageBox.Show(ex.GetType().ToString() + ":\n\n" + ex.Message, MethodName, MessageBoxButton.OK, MessageBoxImage.Stop);
            System.Diagnostics.Process proc = System.Diagnostics.Process.GetCurrentProcess();
            proc.Kill();
        }
    }

    #endregion "Helper Classes"

}
